/*
 * This file is part of Aion-Finish <Ver:3.7>
 *
 *  Aion-Finish is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Aion-Finish is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Aion-Finish.  If not, see <http://www.gnu.org/licenses/>.
 */
package gameserver.services;

import gameserver.configs.main.CustomConfig;
import gameserver.configs.main.LoggingConfig;
import gameserver.dataholders.DataManager;
import gameserver.model.DescriptionId;
import gameserver.model.gameobjects.AionObject;
import gameserver.model.gameobjects.StaticObject;
import gameserver.model.gameobjects.player.Player;
import gameserver.model.templates.item.ItemTemplate;
import gameserver.model.templates.recipe.ComboProduct;
import gameserver.model.templates.recipe.Component;
import gameserver.model.templates.recipe.RecipeTemplate;
import gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import gameserver.services.item.ItemService;
import gameserver.skill.model.SkillTemplate;
import gameserver.skill.task.CraftingTask;
import gameserver.utils.MathUtil;
import gameserver.utils.PacketSendUtility;
import gameserver.world.World;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import commons.utils.Rnd;

/**
 * @author MrPoke, sphinx, HellBoy
 */
public class CraftService {
    private static final Logger log = LoggerFactory.getLogger("CRAFT_LOG");

    /**
     * @param player
     * @param recipetemplate
     */
    public static ItemTemplate finishCrafting(Player player, RecipeTemplate recipetemplate, int itemId) {
        boolean critical = false;
        boolean getReward = false;
        int critItemId = 0;

        if (recipetemplate.getComboProduct().isEmpty()) {
            getReward = true;
        } else {
            critical = Rnd.get(100) <= CustomConfig.CRITICAL_CRAFTING_SUCCESS;
        }

        if (critical) {
            boolean getNext = false;

            for (ComboProduct comboProduct : recipetemplate.getComboProduct()) {
                if ((itemId == recipetemplate.getProductid()) && (critItemId == 0)) {
                    critItemId = comboProduct.getItemid();

                    break;
                } else if (itemId == comboProduct.getItemid()) {
                    getNext = true;
                } else if (getNext) {
                    critItemId = comboProduct.getItemid();

                    break;
                }
            }

            if (critItemId == 0) {
                getReward = true;
            }
        } else {
            getReward = true;
        }

        if (critical && !getReward) {
            return ItemService.getItemTemplate(critItemId);
        } else {
            int productItemId = itemId;
            int skillId = recipetemplate.getSkillid();

            if (recipetemplate.getMaxProductionCount() == 1) {
                player.getRecipeList().deleteRecipe(player, recipetemplate.getId());
            }

            if (skillId == 40009) {
                ItemService.addItem(player, productItemId, recipetemplate.getQuantity(), player.getName(), 0, 0);
                PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_COMBINE_SUCCESS(new DescriptionId(
                        ItemService.getItemTemplate(productItemId).getNameId())));
            } else if ((productItemId != 0) && (skillId != 40009)) {
                int skillPoint = recipetemplate.getSkillpoint();
                SkillTemplate skillTemplate = DataManager.SKILL_DATA.getSkillTemplate(skillId);

                ItemService.addItem(player, productItemId, recipetemplate.getQuantity(), player.getName(), 0, 0);
                ItemTemplate itemTemplate = DataManager.ITEM_DATA.getItemTemplate(productItemId);
                if (LoggingConfig.LOG_CRAFT) {
        			log.info(new StringBuilder().append(critItemId > 0 ? "[CRAFT][Critical] ID/Count" : "[CRAFT][Normal] ID/Count").append(
        					LoggingConfig.ENABLE_ADVANCED_LOGGING ? new StringBuilder().append("/Item Name - ").append(productItemId).append("/").append(recipetemplate.getQuantity()).append("/")
        						.append(itemTemplate.getName()).toString() : new StringBuilder().append(" - ").append(productItemId).append("/").append(recipetemplate.getQuantity()).toString())
        				.append(" to player ").append(player.getName()).toString());
        		}

                if ((skillPoint + 40) > player.getSkillList().getSkillLevel(skillId)) {
                    int xpReward = (int) (((0.0144 * skillPoint * skillPoint) + (3.5 * skillPoint) + 270) * player
                            .getRates().getCraftingLvlRate());

                    if (player.getXpBoost() > 0) {
                        xpReward = xpReward * ((player.getXpBoost() / 100) + 1);
                    }

                    if (player.getSkillList().addSkillXp(player, skillId, xpReward)) {
                        player.getCommonData().addExp(
                                (int) ((xpReward * player.getRates().getCraftingXPRate()) / player.getRates()
                                        .getCraftingLvlRate()));
                        PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CRAFT_SUCCESS_GETEXP);
                    } else {
                        PacketSendUtility
                                .sendPacket(player, SM_SYSTEM_MESSAGE.MSG_DONT_GET_PRODUCTION_EXP(new DescriptionId(
                                        skillTemplate.getNameId())));
                    }
                } else {
                    PacketSendUtility.sendPacket(player,
                            SM_SYSTEM_MESSAGE.MSG_DONT_GET_PRODUCTION_EXP(new DescriptionId(skillTemplate.getNameId())));
                }
            }

            if (recipetemplate.getCraftDelayId() != null) {
                player.getCraftCooldownList().addCraftCooldown(recipetemplate.getCraftDelayId(), recipetemplate.getCraftDelayTime());
            }

            player.setCraftingTask(null);

            return null;
        }
    }

    /**
     * @param player
     * @param targetTemplateId
     * @param recipeId
     * @param targetObjId
     */

    /*
      * public static void startComboCrafting(Player player, RecipeTemplate recipeTemplate, int itemId, int targetObjId)
      * { if (recipeTemplate != null) { AionObject target = World.getInstance().findAionObject(targetObjId); ItemTemplate
      * itemTemplate = ItemService.getItemTemplate(itemId); player.setCraftingTask(new CraftingTask(player,
      * (StaticObject) target, recipeTemplate, itemTemplate)); player.getCraftingTask().combo(); } }
      */

    /**
     * @param player
     * @param recipeId
     * @param targetObjId
     */
    public static void startCrafting(Player player, int recipeId, int targetObjId) {
        if ((player.getCraftingTask() != null) && player.getCraftingTask().isInProgress()) {
            return;
        }

        RecipeTemplate recipeTemplate = DataManager.RECIPE_DATA.getRecipeTemplateById(recipeId);

        if (recipeTemplate == null) {
            log.warn(String.format("recipeTemplate with id %d not found", recipeId));

            return;
        }

        // check for pre-usage crafting
        int skillId = recipeTemplate.getSkillid();
        AionObject target = World.getInstance().findVisibleObject(targetObjId);

        // morphing dont need static object/npc to use
        if ((skillId != 40009) && ((target == null) || !(target instanceof StaticObject))) {
            log.info("[AUDIT] Player " + player.getName() + " tried to craft incorrect target.");

            return;
        }

        // check distance to avoid sending of fake packets
        if ((skillId != 40009) && !MathUtil.isIn3dRange(player, (StaticObject) target, 10)) {
            log.info("[AUDIT] Player " + player.getName() + " sending fake packet CM_CRAFT.");

            return;
        }

        if ((recipeTemplate.getDp() != null) && (player.getCommonData().getDp() < recipeTemplate.getDp())) {
            log.info("[AUDIT] Player " + player.getName() + " modded her/his client.");

            return;
        }

        if (player.getInventory().isFull()) {
            PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.COMBINE_INVENTORY_IS_FULL);

            return;
        }

        if (recipeTemplate.getCraftDelayId() != null) {
            if (!player.getCraftCooldownList().isCanCraft(recipeTemplate.getCraftDelayId())) {
                log.info("[AUDIT] Player " + player.getName() + " try craft item before cooldown expire.");
                return;
            }
        }

        for (Component component : recipeTemplate.getComponent()) {
            if (player.getInventory().getItemCountByItemId(component.getItemid()) < component.getQuantity()) {
                log.info("[AUDIT] Player " + player.getName() + " modded her/his client.");

                return;
            }
        }

        ItemTemplate itemTemplate = ItemService.getItemTemplate(recipeTemplate.getProductid());

        if (itemTemplate == null) {
            log.warn(String.format("itemTemplate with id %d not found", recipeTemplate.getProductid()));

            return;
        }

        if (recipeTemplate.getDp() != null) {
            player.getCommonData().addDp(-recipeTemplate.getDp());
        }

        for (Component component : recipeTemplate.getComponent()) {
            if (!player.getInventory().removeFromBagByItemId(component.getItemid(), component.getQuantity())) {
                return;
            }
        }

        // start crafting
        player.setCraftingTask(new CraftingTask(player, (StaticObject) target, recipeTemplate, itemTemplate));

        player.getCraftingTask().start();
    }
}
